<template>
  <div class="page-table">
    <Table
      ref="selection"
      :size="size"
      :border="border"
      :columns="getColumns"
      :data="getPageData"
      :loading="loading"
      :width="width"
      :max-height="maxHeight"
      :row-class-name="rowClassName"
      :show-summary="showSummary"
      @on-select-cancel="onSelectCancel"
      @on-selection-change="onSelectChange"
      @on-filter-change="onFilterChange"
      @on-sort-change="onSorterChange"
      @on-expand="onExpand"
    >
    </Table>

    <Row v-if="hasPagination" type="flex" justify="end" style="margin-top: 16px;">
      <Page
        :total="getPagination.total"
        :current="getPagination.current"
        :page-size="getPagination.pageSize"
        :page-size-opts="getPagination.pageSizeOpts"
        :show-total="getPagination.showTotal"
        :show-sizer="showSizer"
        @on-change="onPageChange"
        @on-page-size-change="onPageSizeChange"
      />
    </Row>
  </div>
</template>
<script>
import _ from 'lodash'
import { toJS } from '@/libs/object'

const DEFAULT_PAGINATION = {
  current: 1,
  pageSize: 15,
  onChange: _.noop,
  onShowSizeChange: _.noop,
  showTotal: true,
  pageSizeOpts: [15, 30, 50, 100]
}
const DEFAULT_SORTABLE = {
  key: '',
  column: {},
  order: 'normal' // normal asc desc
}
const exceptCheckAndDisable = row => _.omit(row, ['_checked', '_disabled'])
export default {
  name: 'PageTable',
  props: {
    columns: {
      type: Array,
      default: () => []
    },
    data: {
      type: Array,
      default: () => []
    },
    loading: {
      type: Boolean,
      default: false
    },
    showSummary: {
      type: Boolean,
      default: false
    },
    pagination: {
      type: [Boolean, Object],
      default: () => ({})
    },
    border: {
      type: Boolean,
      default: false
    },
    showSizer: {
      type: Boolean,
      default: true
    },
    selected: {
      type: Array,
      default: () => []
    },
    disableSelected: {
      type: Array,
      default: () => []
    },
    size: {
      type: String,
      default: () => 'large'
    },
    width: {
      type: String,
      default: () => 'auto'
    },
    maxHeight: {
      type: [Number, String],
      default: '200'
    },
    rowClassName: {
      type: Function,
      default: () => {
        return ''
      }
    }
  },
  data() {
    const pagination = {
      ...DEFAULT_PAGINATION,
      ...this.pagination
    }
    return {
      sorter: DEFAULT_SORTABLE,
      selections: this.selected,
      conditions: [],
      currentPage: pagination.current,
      currentPageSize: pagination.pageSize
    }
  },
  computed: {
    getColumns() {
      return this.columns
    },
    getFilterData() {
      let filterData = this.data
      // 多个条件，多条件间是 与 的关系
      for (const { key, filters } of this.conditions) {
        const { filterMethod } = _.find(this.getColumns, { key })
        // 如果没有设定筛选函数，则默认不命中
        if (!filterMethod) {
          return
        }
        const conditionFilters = _.isArray(filters) ? filters : [filters]
        if (_.isEmpty(conditionFilters)) {
          return
        }
        // 多选 符合选中条件， 符合任一选项，选项间是 或 的关系
        filterData = filterData.filter(row => _.some(conditionFilters, condition => filterMethod(condition, row)))
      }
      return filterData
    },
    getPageData() {
      const filterData = this.getFilterData
      if (!this.hasPagination) {
        let pageData = this.getSorterData(filterData)
        pageData = _.map(pageData, exceptCheckAndDisable)
        return this.fillDisableSelectRows(this.fillSelectRows(pageData))
      }
      const sortData = this.getSorterData(filterData)
      const { currentPage, currentPageSize } = this
      let pageData = sortData
      // 服务端分页，data大于一页时，需要本地再分页
      if (sortData.length > currentPageSize) {
        pageData = sortData.slice((currentPage - 1) * currentPageSize, currentPage * currentPageSize)
      }
      pageData = _.map(pageData, exceptCheckAndDisable)
      return this.fillDisableSelectRows(this.fillSelectRows(pageData))
    },
    getPagination() {
      if (!this.hasPagination) {
        return {}
      }
      return {
        ...DEFAULT_PAGINATION,
        ...this.pagination,
        current: this.pagination.current || this.currentPage || this.pagination.defaultCurrent,
        pageSize: this.currentPageSize || this.pagination.pageSize || this.pagination.defaultPageSize,
        total: this.pagination.total || this.getFilterData.length
      }
    },
    hasPagination() {
      // pagination === false 不需要分页
      return this.pagination !== false
    }
  },
  watch: {
    selected(newVal) {
      this.selections = newVal
    }
  },
  methods: {
    onChange() {
      const { key: field, order } = this.sorter
      const buildFilters = conditions => {
        const filter = {}
        for (const { key, filters } of conditions) {
          filter[key] = toJS(filters)
        }
        return filter
      }
      const pagination = this.getPagination
      // pagination, filters, sorter
      this.$emit('on-change', { ...pagination, current: this.currentPage }, buildFilters(this.conditions), {
        field,
        order
      })
    },
    onSelectChange(rows) {
      if (rows.length === 0) {
        // 重置筛选
        this.selections = rows
        this.$emit('on-selection-change', [])
        return
      }
      // this.selections 已选中
      // newRows 本次选中
      const newRows = []
      rows.forEach(row => {
        if (!_.find(this.selections, s => _.isEqual(toJS(s), exceptCheckAndDisable(row)))) {
          newRows.push(row)
        }
      })
      this.selections = this.selections.concat(newRows)
      this.$emit('on-selection-change', toJS(this.selections))
    },
    onSelectCancel(selection, row) {
      this.selections = _.filter(this.selections, s => !_.isEqual(toJS(s), exceptCheckAndDisable(row)))
    },
    onFilterChange({ key, _filterChecked }) {
      // 修改已有过滤条件
      if (_.find(this.conditions, c => c.key === key)) {
        _.remove(this.conditions, c => c.key === key)
      }
      // 非重置条件
      if (!_.isEmpty(_filterChecked)) {
        this.conditions.push({
          key,
          filters: _filterChecked
        })
      }
      // 重置条件时，不修改condition，判断不到变更
      this.conditions = [...this.conditions]
      // 修改过滤条件，重置分页
      this.currentPage = 1
      // onchange
      this.onChange()
    },
    onSorterChange({ column, key, order }) {
      if (order === 'normal') {
        key = ''
      }
      this.sorter = {
        column,
        key,
        order
      }
      // onchange
      this.onChange()
    },
    onPageChange(page) {
      this.currentPage = page
      // onchange
      this.onChange()
    },
    onPageSizeChange(pageSize) {
      this.currentPageSize = pageSize
      // onchange
      this.onChange()
    },
    getSorterData(data) {
      const { key, order } = this.sorter
      if (key === '') {
        return data
      }
      return _.orderBy(data, [key], [order])
    },
    fillSelectRows(data) {
      const { selections } = this
      return _.map(data, row => {
        if (_.find(selections, s => _.isEqual(toJS(s), exceptCheckAndDisable(row)))) {
          row._checked = true
        }
        return row
      })
    },
    fillDisableSelectRows(data) {
      const { disableSelected } = this
      return _.map(data, row => {
        if (_.find(disableSelected, d => _.isEqual(toJS(d), exceptCheckAndDisable(row)))) {
          row._disabled = true
        }
        return row
      })
    },
    onExpand(row, status) {
      this.$emit('on-expand', row, status)
    }
  }
}
</script>

<style lang="scss">
.page-table {
  .ivu-table .table-info-row td {
    background-color: #0fd619 !important;
  }
  .ivu-table .table-grey-row td {
    background-color: #f8f8f9 !important;
  }
  .ivu-table .white-background-row td {
    background-color: white !important;
  }
}
</style>
